home *** CD-ROM | disk | FTP | other *** search
- #include "gllandscape.h"
-
- #ifdef Q_WS_MAC
- #include <gl.h>
- #include <glu.h>
- #else
- #include <GL/gl.h>
- #include <GL/glu.h>
- #endif
-
- #include <math.h>
-
- #include "fbm.h"
-
- #ifndef PI
- #define PI 3.14159
- #endif
-
- #if defined(Q_CC_MSVC)
- #pragma warning(disable:4305) // init: truncation from const double to float
- #pragma warning(disable:4244) // init: truncation from const double to float
- #endif
-
- GLLandscape::GLLandscape( QWidget * parent, const char * name )
- : QGLWidget( parent, name )
- {
- mouseButtonDown = FALSE;
- animationRunning = FALSE;
- oldX = oldY = oldZ = 0.0;
- landscape = 0;
- vertexNormals = 0;
- normals = 0;
- wave = 0;
- wt = 0;
- createGrid( 50 );
- setWireframe( 0 );
- }
-
- GLLandscape::~GLLandscape()
- {
- destroyGrid();
- }
-
- void GLLandscape::initializeGL()
- {
- glMatrixMode( GL_MODELVIEW );
- glLoadIdentity();
- glTranslatef( 0.0, 0.0, -50.0 );
- glRotatef( -45, 1, 0, 0 );
- glRotatef( -45, 0, 0, 1 );
- glGetFloatv( GL_MODELVIEW_MATRIX,(GLfloat *) views[CurrentView].model );
- glGetFloatv( GL_MODELVIEW_MATRIX,(GLfloat *) views[DefaultView].model );
-
- glMatrixMode( GL_PROJECTION );
- glLoadIdentity();
- /* Use GL utility library function to obtain desired view */
- gluPerspective( 60, 1, 1, 250 );
- glGetFloatv( GL_PROJECTION_MATRIX, (GLfloat *)views[CurrentView].projection );
- glGetFloatv( GL_PROJECTION_MATRIX, (GLfloat *)views[DefaultView].projection );
-
-
- qglClearColor( black );
- glDepthFunc( GL_LESS );
- calculateVertexNormals();
- }
-
- void GLLandscape::resizeGL( int width, int height )
- {
- glViewport( 0, 0, width, height );
- }
-
- void GLLandscape::paintGL()
- {
- glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
- switch ( mode ) {
- case Wireframe:
- drawWireframe();
- break;
- case Filled:
- drawFilled();
- break;
- case SmoothShaded:
- case Landscape:
- drawSmoothShaded();
- break;
- }
- }
-
- void GLLandscape::drawWireframe()
- {
- qglColor( white );
- glBegin( GL_LINES );
- {
- for ( int y = 0; y < (gridSize-1); y++ )
- for ( int x = 0; x < (gridSize-1); x++) {
- glVertex3f( x-gridHalf, y-gridHalf, landscape[x][y] );
- glVertex3f( x+1-gridHalf, y-gridHalf, landscape[x+1][y] );
- glVertex3f( x-gridHalf, y-gridHalf, landscape[x][y] );
- glVertex3f( x+1-gridHalf, y+1-gridHalf, landscape[x+1][y+1] );
-
- glVertex3f( x-gridHalf, y-gridHalf, landscape[x][y] );
- glVertex3f( x-gridHalf, y+1-gridHalf, landscape[x][y+1] );
- }
- }
- glEnd();
- glBegin( GL_LINE_STRIP );
- {
- for ( int x = 0; x < gridSize; x++ ) {
- glVertex3f( x-gridHalf, gridHalf-1, landscape[x][gridSize-1] );
- }
- }
- glEnd();
- glBegin( GL_LINE_STRIP );
- {
- for ( int y = 0; y < gridSize; y++ ) {
- glVertex3f( gridHalf-1, y-gridHalf, landscape[gridSize-1][y] );
- }
- }
- glEnd();
- }
-
- void GLLandscape::drawFilled()
- {
- for ( int y = 0; y < gridSize-1; y++ )
- for ( int x = 0; x < gridSize-1; x++ ) {
- qglColor( red );
- glBegin( GL_TRIANGLE_STRIP );
- {
- glVertex3f(x-gridHalf,y-gridHalf, landscape[x][y]);
- glVertex3f(x+1-gridHalf,y-gridHalf, landscape[x+1][y]);
- glVertex3f(x-gridHalf,y+1-gridHalf, landscape[x][y+1]);
- }
- glEnd();
- qglColor( white );
- glBegin( GL_TRIANGLE_STRIP );
- {
- glVertex3f(x+1-gridHalf,y-gridHalf, landscape[x+1][y]);
- glVertex3f(x+1-gridHalf,y+1-gridHalf, landscape[x+1][y+1]);
- glVertex3f(x-gridHalf,y+1-gridHalf, landscape[x][y+1]);
- }
- glEnd();
- }
- }
-
- void GLLandscape::drawSmoothShaded()
- {
- if ( mode == SmoothShaded ) {
- GLfloat materialAmbient[] = { 0.00, 0.00, 1.0, 0.0 };
- GLfloat materialShininess[] = { 128.0 };
- GLfloat materialSpecular[] = { 1.0, 1.0, 1.0, 0.0 };
-
- glMaterialfv( GL_FRONT, GL_SPECULAR, materialSpecular );
- glMaterialfv( GL_FRONT, GL_AMBIENT, materialAmbient );
- glMaterialfv( GL_FRONT, GL_SHININESS, materialShininess );
- } else {
- GLfloat materialAmbient[] = { 0.20, 0.33, 0.20, 0.0 };
- GLfloat materialShininess[] = { 1.0 };
- GLfloat materialSpecular[] = { 0.1, 0.1, 0.1, 0.1 };
-
- glMaterialfv( GL_FRONT, GL_SPECULAR, materialSpecular );
- glMaterialfv( GL_FRONT, GL_AMBIENT, materialAmbient );
- glMaterialfv( GL_FRONT, GL_SHININESS, materialShininess );
- }
-
- for ( int y = 0; y < gridSize-1; y++ )
- for ( int x = 0; x < gridSize-1; x++ ) {
- glBegin( GL_POLYGON );
- {
- glNormal3dv(vertexNormals[x][y].n);
- glVertex3f(x-gridHalf,y-gridHalf,landscape[x][y]);
-
- glNormal3dv(vertexNormals[x+1][y].n);
- glVertex3f(x+1-gridHalf, y-gridHalf, landscape[x+1][y]);
-
- glNormal3dv(vertexNormals[x+1][y+1].n);
- glVertex3f(x+1-gridHalf, y+1-gridHalf, landscape[x+1][y+1]);
- }
- glEnd();
-
- glBegin( GL_POLYGON );
- {
- glNormal3dv(vertexNormals[x][y].n);
- glVertex3f(x-gridHalf,y-gridHalf, landscape[x][y]);
-
- glNormal3dv(vertexNormals[x+1][y+1].n);
- glVertex3f(x+1-gridHalf,y+1-gridHalf, landscape[x+1][y+1]);
-
- glNormal3dv(vertexNormals[x][y+1].n);
- glVertex3f(x-gridHalf,y+1-gridHalf, landscape[x][y+1]);
- }
- glEnd();
- }
-
- // Draw water
- if ( mode == Landscape ) {
- GLfloat materialAmbient[] = { 0.00, 0.00, 1.0, 0.0 };
- GLfloat materialShininess[] = { 128.0 };
- GLfloat materialSpecular[] = { 1.0, 1.0, 1.0, 0.0 };
-
- glMaterialfv( GL_FRONT, GL_SPECULAR, materialSpecular );
- glMaterialfv( GL_FRONT, GL_AMBIENT, materialAmbient );
- glMaterialfv( GL_FRONT, GL_SHININESS, materialShininess );
-
- glEnable( GL_BLEND );
- glBegin( GL_POLYGON );
- {
- glNormal3f( 0, 0, 1 );
- glVertex3f( -gridHalf, -gridHalf, .2 );
- glNormal3f( 0, 0, 1 );
- glVertex3f( -gridHalf, gridHalf, .2 );
- glNormal3f( 0, 0, 1 );
- glVertex3f( gridHalf, gridHalf, .2 );
- glNormal3f( 0, 0, 1 );
- glVertex3f( gridHalf, -gridHalf, .2 );
-
- }
- glEnd();
- glDisable( GL_BLEND );
- }
- }
-
- void GLLandscape::setGridSize( int size )
- {
- destroyGrid(); // destroy old grid
- createGrid( size ); // create new grid
- initializeGL();
- updateGL();
- }
-
- void GLLandscape::createGrid( int size )
- {
- if ( (size % 2) != 0 )
- size++;
- gridSize = size;
- gridHalf = gridSize / 2;
- initFractals = TRUE;
- landscape = new double*[gridSize];
- normals = new gridNormals*[gridSize];
- vertexNormals = new avgNormals*[gridSize];
- wt = new double*[gridSize];
- wave = new double*[gridSize];
- for ( int i = 0; i < gridSize; i++ ) {
- landscape[i] = new double[gridSize];
- normals[i] = new gridNormals[gridSize];
- vertexNormals[i] = new avgNormals[gridSize];
- wt[i] = new double[gridSize];
- wave[i] = new double[gridSize];
-
- memset( landscape[i], 0, gridSize*sizeof(double) );
- memset( normals[i], 0, gridSize*sizeof(gridNormals) );
- memset( vertexNormals[i], 0, gridSize*sizeof(avgNormals) );
- memset( wt[i], 0, gridSize*sizeof(double) );
- memset( wave[i], 0, gridSize*sizeof(double) );
- }
- }
-
- void GLLandscape::destroyGrid()
- {
- if ( landscape != NULL ) {
- for( int i = 0; i < gridSize; i++ ) {
- delete[] landscape[i];
- delete[] normals[i];
- delete[] vertexNormals[i];
- delete[] wt[i];
- delete[] wave[i];
- }
- delete[] landscape;
- delete[] normals;
- delete[] vertexNormals;
- delete[] wt;
- delete[] wave;
- }
- landscape = 0;
- }
-
- void GLLandscape::rotate( GLfloat deg, Axis axis )
- {
- makeCurrent();
- glMatrixMode( GL_MODELVIEW );
- for ( int i = 0; i < 2; i++ ) {
- glLoadMatrixf((GLfloat *) views[i].model);
- if ( axis == XAxis )
- glRotatef( deg, 1, 0, 0 );
- else if ( axis == YAxis )
- glRotatef( deg, 0, 1, 0 );
- else
- glRotatef( deg, 0, 0, 1 );
- glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat *) views[i].model);
- }
- glLoadMatrixf((GLfloat *) views[CurrentView].model);
- }
-
- void GLLandscape::rotateX( int deg )
- {
- static int oldDeg = 0;
-
- rotate( deg-oldDeg, XAxis );
- oldDeg = deg;
- updateGL();
- }
-
- void GLLandscape::rotateY( int deg )
- {
- static int oldDeg = 0;
-
- rotate( deg-oldDeg, YAxis );
- oldDeg = deg;
- updateGL();
- }
-
- void GLLandscape::rotateZ( int deg )
- {
- static int oldDeg = 0;
-
- rotate( deg-oldDeg, ZAxis );
- oldDeg = deg;
- updateGL();
- }
-
- void GLLandscape::zoom( int z )
- {
- float zoom;
- if ( z < 100 ) {
- zoom = 1 + 4.99 - (z*5.0 / 100.0);
- } else {
- z = 200 - z;
- zoom = z / 100.0;
- }
- makeCurrent();
- glMatrixMode( GL_MODELVIEW );
- // Always scale the original model matrix
- glLoadMatrixf((GLfloat *) views[DefaultView].model);
- glScalef( zoom, zoom, zoom );
- glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat *) views[CurrentView].model);
- updateGL();
- }
-
- void GLLandscape::resetGrid()
- {
- setGridSize( gridSize );
- }
-
- void GLLandscape::fractalize()
- {
- Vector p;
- double value;
- double roughness = 0.5;
- int frequency = 50;
-
- p.x = p.y = p.z = 0;
- // Initialise fbm routine
- if ( initFractals ) {
- initFractals = FALSE;
- value = fBm( p, roughness, 2.0, 8.0, 1 );
- }
-
- // Fractalize grid
- for ( int x = 0; x < gridSize; x++ ) {
- for ( int y = 0; y < gridSize; y++ ) {
- p.x = (double) x / (101 - frequency);
- p.y = (double) y / (101 - frequency);
- p.z = (double) landscape[x][y] / (101 - frequency);
- value = fBm(p, roughness, 2.0, 8.0, 0);
- landscape[x][y] += value;
- }
- }
- calculateVertexNormals();
- updateGL();
- }
-
-
- //
- // Calculate the vector cross product of v and w, store result in n.
- //
- static void crossProduct( double v[3], double w[3], double n[3] )
- {
- n[0] = v[1]*w[2]-w[1]*v[2];
- n[1] = w[0]*v[2]-v[0]*w[2];
- n[2] = v[0]*w[1]-w[0]*v[1];
- }
-
- void GLLandscape::calculateVertexNormals()
- {
- double len, v[3], v2[3], w[3], w2[3], n[3], n2[3];
-
- // Calculate the surface normals for all polygons in the
- // height field
- for ( int i = 0; i < (gridSize-1); i++ )
- for ( int k = 0; k < (gridSize-1); k++ ) {
- /* Lower poly normal */
- v[0] = 1; // (i+1)-i
- v[1] = 0; // k-k
- v[2] = landscape[i+1][k]-landscape[i][k];
- w[0] = 1; // (i+1)-i
- w[1] = 1; // (k+1)-k
- w[2] = landscape[i+1][k+1]-landscape[i][k];
- crossProduct( v, w, n );
- len = sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]);
- normals[i][k].l[0] = n[0]/len;
- normals[i][k].l[1] = n[1]/len;
- normals[i][k].l[2] = n[2]/len;
-
- /* Upper poly normal */
- v2[0] = -1.0; // i-(i+1);
- v2[1] = 0.0; // (k+1)-(k+1);
- v2[2] = landscape[i][k+1]-landscape[i+1][k+1];
- w2[0] = -1.0; // i-(i+1);
- w2[1] = -1.0; // k-(k+1);
- w2[2] = landscape[i][k]-landscape[i+1][k+1];
- crossProduct( v2, w2, n2 );
- len = sqrt(n2[0]*n2[0]+n2[1]*n2[1]+n2[2]*n2[2]);
- normals[i][k].u[0] = n2[0]/len;
- normals[i][k].u[1] = n2[1]/len;
- normals[i][k].u[2] = n2[2]/len;
- }
-
- // Calculate proper vertex normals
- averageNormals();
- }
-
- void GLLandscape::averageNormals()
- {
- // Calculate the average surface normal for a vertex based on
- // the normals of the surrounding polygons
- for ( int i = 0; i < gridSize; i++ )
- for ( int k = 0; k < gridSize; k++ ) {
- if ( i > 0 && k > 0 && i < (gridSize-1) && k < (gridSize-1) ) {
- // For vertices that are *not* on the edge of the height field
- for ( int t = 0; t < 3; t++ ) // X, Y and Z components
- vertexNormals[i][k].n[t] = ( normals[i][k].u[t] +
- normals[i][k].l[t] +
- normals[i][k-1].u[t] +
- normals[i-1][k-1].u[t] +
- normals[i-1][k-1].l[t] +
- normals[i-1][k].l[t] )/6.0;
- } else {
- // Vertices that are on the edge of the height field require
- // special attention..
- if ( i == 0 && k == 0 ) {
- for ( int t = 0; t < 3; t++ )
- vertexNormals[i][k].n[t] = ( normals[i][k].u[t] +
- normals[i][k].l[t] )/2.0;
- } else if ( i == gridSize-1 && k == gridSize-1 ) {
- for ( int t = 0; t < 3; t++ )
- vertexNormals[i][k].n[t] = ( normals[i][k].u[t] +
- normals[i][k].l[t] )/2.0;
- } else if ( i == gridSize-1) {
- for ( int t = 0; t < 3; t++ )
- vertexNormals[i][k].n[t] = vertexNormals[i-1][k].n[t];
- } else if ( k == gridSize-1 ) {
- for ( int t = 0; t < 3; t++ )
- vertexNormals[i][k].n[t] = vertexNormals[i][k-1].n[t];
- } else if ( k > 0 ) {
- for ( int t = 0; t < 3; t++ )
- vertexNormals[i][k].n[t] = (normals[i][k].u[t] +
- normals[i][k].l[t] +
- normals[i][k-1].u[t])/3.0;
- } else if ( i > 0 ) {
- for ( int t = 0; t < 3; t++ )
- vertexNormals[i][k].n[t] = (normals[i][k].u[t] +
- normals[i][k].l[t] +
- normals[i-1][k].l[t])/3.0;
- }
- }
- }
- }
-
- void GLLandscape::setWireframe( int state )
- {
- if ( state != 1 ) {
- // Enable line antialiasing
- makeCurrent();
- glEnable( GL_LINE_SMOOTH );
- glEnable( GL_BLEND );
- glDisable( GL_DEPTH_TEST );
- glDisable( GL_LIGHTING );
- glDisable( GL_NORMALIZE );
-
- glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
- glHint( GL_LINE_SMOOTH_HINT, GL_DONT_CARE );
-
- mode = Wireframe;
- updateGL();
- }
- }
-
- void GLLandscape::setFilled( int state )
- {
- if ( state != 1 ) {
- makeCurrent();
- glEnable( GL_DEPTH_TEST );
- glDisable( GL_LINE_SMOOTH );
- glDisable( GL_BLEND );
- glDisable( GL_LIGHTING );
- glDisable( GL_NORMALIZE );
-
- mode = Filled;
- updateGL();
- }
- }
-
- void GLLandscape::setSmoothShaded( int state )
- {
- if ( state != 1 ) {
- makeCurrent();
- glEnable( GL_DEPTH_TEST );
- glEnable( GL_LIGHTING );
- glEnable( GL_LIGHT0 );
- glEnable( GL_NORMALIZE );
- glDisable( GL_LINE_SMOOTH );
- glDisable( GL_BLEND );
-
- glShadeModel( GL_SMOOTH );
- glLightModeli( GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE );
-
- // Setup lighting and material properties
- GLfloat position[] = { 15.0, -15.0, 15.0, 0.0 };
- GLfloat ambient[] = { 0.50, 0.50, 0.50, 0.0 };
- GLfloat diffuse[] = { 1.00, 1.00, 1.00, 0.0 };
- GLfloat specular[] = { 1.0, 1.0, 1.0, 0.0 };
- GLfloat materialAmbient[] = { 0.00, 0.00, 1.0, 0.0 };
- // GLfloat materialDiffuse[] = { 1.00, 1.00, 1.0, 0.0 };
- GLfloat materialShininess[] = { 128.0 };
- GLfloat materialSpecular[] = { 1.0, 1.0, 1.0, 0.0 };
-
- glMaterialfv( GL_FRONT, GL_SPECULAR, materialSpecular );
- // glMaterialfv( GL_FRONT, GL_DIFFUSE, materialDiffuse );
- glMaterialfv( GL_FRONT, GL_AMBIENT, materialAmbient );
- glMaterialfv( GL_FRONT, GL_SHININESS, materialShininess );
-
- glLightfv( GL_LIGHT0, GL_POSITION, position );
- glLightfv( GL_LIGHT0, GL_AMBIENT, ambient );
- glLightfv( GL_LIGHT0, GL_DIFFUSE, diffuse );
- glLightfv( GL_LIGHT0, GL_SPECULAR, specular );
-
- mode = SmoothShaded;
- calculateVertexNormals();
- updateGL();
- }
- }
-
- void GLLandscape::setLandscape( int state )
- {
- if ( state != 1 ) {
- makeCurrent();
- glEnable( GL_DEPTH_TEST );
- glEnable( GL_LIGHTING );
- glEnable( GL_LIGHT0 );
- glEnable( GL_NORMALIZE );
- glDisable( GL_LINE_SMOOTH );
- glDisable( GL_BLEND );
-
- glShadeModel( GL_SMOOTH );
- glLightModeli( GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE );
-
- // Setup lighting and material properties
- GLfloat position[] = { 15.0, -15.0, 15.0, 0.0 };
- GLfloat ambient[] = { 0.50, 0.50, 0.50, 0.0 };
- GLfloat diffuse[] = { 1.00, 1.00, 1.00, 0.0 };
- GLfloat specular[] = { 1.0, 1.0, 1.0, 0.0 };
-
- glLightfv( GL_LIGHT0, GL_POSITION, position );
- glLightfv( GL_LIGHT0, GL_AMBIENT, ambient );
- glLightfv( GL_LIGHT0, GL_DIFFUSE, diffuse );
- glLightfv( GL_LIGHT0, GL_SPECULAR, specular );
-
- glBlendFunc(GL_SRC_ALPHA, GL_SRC_COLOR );
-
- mode = Landscape;
- calculateVertexNormals();
- updateGL();
- }
- }
-
- void GLLandscape::mousePressEvent( QMouseEvent *e )
- {
- oldPos = e->pos();
- mouseButtonDown = TRUE;
- }
-
- void GLLandscape::mouseReleaseEvent( QMouseEvent *e )
- {
- oldPos = e->pos();
- mouseButtonDown = FALSE;
- }
-
- void GLLandscape::mouseMoveEvent( QMouseEvent *e )
- {
- GLfloat rx = (GLfloat) (e->x() - oldPos.x()) / width();
- GLfloat ry = (GLfloat) (e->y() - oldPos.y()) / height();
-
- if ( e->state() == LeftButton ) {
- // Left button down - rotate around X and Y axes
- oldX = 180*ry;
- oldY = 180*rx;
- rotate( oldX, XAxis );
- rotate( oldY, YAxis );
- updateGL();
- } else if ( e->state() == RightButton ) {
- // Right button down - rotate around X and Z axes
- oldX = 180*ry;
- oldZ = 180*rx;
- rotate( oldX, XAxis );
- rotate( oldZ, ZAxis );
- updateGL();
- }
- oldPos = e->pos();
- }
-
- void GLLandscape::timerEvent( QTimerEvent * )
- {
- int dx, dy; // disturbance point
- float s, v, W, t;
- int i, j;
-
- if ( mode == Landscape ) {
- dx = dy = 0;
- } else {
- dx = dy = gridSize >> 1;
- }
- W = 0.3;
- v = -4; // wave speed
-
- for ( i = 0; i < gridSize; i++ )
- for ( j = 0; j < gridSize; j++ )
- {
- s = sqrt( (double) ( (j - dx) * (j - dx) + (i - dy) * (i - dy) ) );
- wt[i][j] += 0.1;
- t = s / v;
-
- if ( mode == Landscape ) {
- if ( (landscape[i][j] + wave[i][j]) < 0 )
- landscape[i][j] -= wave[i][j];
- if ( (dy - j != 0) || (dx - i != 0) )
- wave[i][j] = (3 * sin( 2 * PI * W * (wt[i][j] + t ))) /
- (0.2*(sqrt( pow((double)(dx-i), 2) + pow((double)(dy-j), 2))+2));
- else
- wave[i][j] = ( 3 * sin( 2 * PI * W * ( wt[i][j] + t ) ) );
- if ( landscape[i][j] + wave[i][j] < 0 )
- landscape[i][j] += wave[i][j];
-
- } else {
- landscape[i][j] -= wave[i][j];
-
- if ( s != 0 )
- wave[i][j] = 2 * sin(2 * PI * W * ( wt[i][j] + t )) /
- (0.2*(s + 2));
- else
- wave[i][j] = 2 * sin( 2 * PI * W * ( wt[i][j] + t ) );
- landscape[i][j] += wave[i][j];
- }
-
- }
- if ( mode == SmoothShaded || mode == Landscape )
- calculateVertexNormals();
- updateGL();
- }
-
- void GLLandscape::toggleWaveAnimation( bool state )
- {
- if ( state ) {
- startTimer( 20 );
- animationRunning = TRUE;
- } else {
- killTimers();
- animationRunning = FALSE;
- }
- }
-
- void GLLandscape::showEvent( QShowEvent * )
- {
- if ( animationRunning )
- startTimer( 20 );
- }
-
- void GLLandscape::hideEvent( QHideEvent * )
- {
- if ( animationRunning )
- killTimers();
- }
-